home *** CD-ROM | disk | FTP | other *** search
- /* This file contains the implementation of the xmodem protocol
- and its varients "Text" and "MacBinary"
-
- Author: Jerry LeVan
- 325 Boone Trail
- Richmond Ky 40475
- New File: May 27,1987
-
- */
- #include <types.h>
- #include <quickdraw.h>
- #include <files.h>
- #include <strings.h>
- #include <setJmp.h>
- #include <dialogs.h>
- #include <packages.h>
- #include <events.h>
- #include <devices.h>
- #include <errors.h>
-
-
- #define FLInit 0x100 /* the init flag */
-
- #define NUL 0
- #define SOH 1
- #define EOT 4
- #define ACK 6
- #define NAK 21
- #define CAN 24
- #define CTLZ 26
- #define CRCCHAR 67
-
- #define CR 13
- #define LF 10
-
- #define GEN1x5x12x16 0x1021
-
- #define ERRLIM 10
- #define NAKLIM 10
- #define EOTLIM 10
- #define ACKLIMTIM 10
- #define NAKTIM 12
-
- /* the following five items track the users xmodem preferences */
- /* they are set in DoMenu in file term.c */
-
- char MacBinary = 1; /* true means try macbinary else standard xmodem */
- char TextXMode = 0; /* true means append Lf after Cr on upload */
- /* and strip Lf after Cr on download */
-
- char fastDL = 0; /* true implies a fast ack */
- char forceCheckSum = 0 ; /* true means disable CRC */
- long sectorSize = 128;
- /******************************************************************/
- /* these variables are defined in term.c */
- extern short sOut; /* output modem refnum */
- extern short sIn; /* input modem refnum */
- extern OSType creator; /* text file creator type */
- extern WindowPtr myWindow; /* tty window pointer */
-
- /* this variable is defined in clock.c */
- extern Boolean showClock;
-
- /* the following items are used by the "in progress" dialog */
- DialogPtr dlog; /* will point to the progress dialog */
- Handle statusHandle; /* for quick access */
-
- #define PROGRESS_ID 131
- #define TRANS_ITEM 13
- #define PROTOCOL_ITEM 14
- #define ERROR_ITEM 15
- #define FILE_ITEM 12
- #define BLOCK_ITEM 6
- #define OF_ITEM 7
- #define TOTAL_ITEM 8
- #define STATUS_ITEM 10
-
-
- char logFileName[64]; /* received file name */
- short logFileRefNum; /* Vol/Dir refnum */
- short logFile; /* channel for FSRead */
-
- char thefilename[64]; /* name of file being sent */
- short thefileRefNum; /* Vol/Dir refnum */
- short thefile; /* channel for FSWrite */
-
- long gTotal; /* total number of blocks to transfer */
-
- /* a table for fast computations of crc's (thanks to Bela Lubkin) */
- unsigned short crc_table[256];
-
- /* a buffer for setjmp/longjmp */
- jmp_buf env;
-
- #define __SEG__ Xmodem
-
- /*********************************code*********************************/
- /* table lookup crc calculations */
-
- unsigned short compute_crc(crc,bufptr,len)
- unsigned short crc;
- char *bufptr;
- short len;
- {
- int i;
- while (len--) {
- crc ^= (unsigned short)(*bufptr++) << 8;
- for (i = 0; i < 8; ++i) {
- if (crc & 0x8000)
- crc = (crc << 1) ^ 0x1021;
- else
- crc <<= 1;
- }
- }
- return(crc);
- }
- setup_crc_tables()
- {
- int count;
- char zero;
-
- zero = 0;
- for (count=0; count<256; count++)
- crc_table[count]=compute_crc(count<<8,&zero,1);
- }
-
- unsigned short table_driven_crc(crc,bufptr,len)
- register unsigned short crc;
- register unsigned char *bufptr;
- register short len;
- {
- while (len--)
- /* on some C systems the index is sign extended */
- crc=crc_table[crc>>8^(*bufptr++)]^crc<<8;
- return(crc);
- }
-
- unsigned char CheckSum(buff,size)
- char * buff;
- short size;
- { unsigned char sum;
- short i;
- sum = 0;
- for(i=0;i<size;i++)
- sum = sum + buff[i];
- return sum;
- }
- /**************************** Utilities *********************************/
- static Boolean ChAvail( chan) /* return true if char avail in serial port */
- short chan;
- { OSErr err;
- long cnt;
- if(err = SerGetBuf(chan,&cnt))return false;
- if (cnt) return true;
- return false;
- }
-
- /* This procedure should be changed to do the timing in a processor
- independent way eg a rom call
- */
- short TimedRead(chan,buff,count,limit)
- short chan;
- char buff[];
- short count;
- long limit;
-
- { long theLimit;
- short i;
- long cnt;
-
- i = 0;
- theLimit = *(long *) 0x20c + limit; /* time stored here */
-
- while (theLimit >= *(long*)0x20c )
- { if(ChAvail(chan))
- { cnt = 1; FSRead(chan,&cnt,&buff[i]); i++;
- if ( i == count ) return 1; /* success */
- }
- }
- return 0; /* failure */
- }
-
- static void OutCh(chan,ch)
- short chan; /* output refnum */
- char ch; /* the character to write */
- { long cnt;
- cnt = 1;
- FSWrite(chan,&cnt,&ch); /* ignore serial port errror for now */
- }
-
- void Cancel(chan,errno)
- short chan;
- short errno;
- { char c;
- void OutCh();
-
- while( TimedRead(chan,&c,1,1)); /* eat garbage */
-
- OutCh(sOut,CAN); /* notify the other end */
-
- while(TimedRead(chan,&c,1,1)); /* eat more trash */
-
- longjmp(env,errno);
- }
-
-
- static void OutBlock(refnum,buff,size)
- short refnum; /* channel to use */
- char * buff; /* address of buffer to write */
- long size; /* the number of chars to write */
- { OSErr err;
- long cnt; /* kludge so write won't change sector size */
- cnt = size;
- if(err = FSWrite(refnum,&cnt,buff)){
- ErrorMessage("Fatal Error Writing File",err);
- Cancel(sIn,6);
- }
- }
-
-
- static void Message(theMessage)
- char * theMessage;
- {
- SetIText(statusHandle,theMessage);
- };
-
- static Boolean FindFile(name,vRefNum)
- char * name; /* name we are looking for */
- short vRefNum; /* dir/vol refnum */
- { FInfo info;
- OSErr err;
- if(err = GetFInfo(name,vRefNum,&info))
- return false;
- else return true;
- }
-
- void SetFileInformation(buff)
- char buff[];
- { char localname[64]; /* prefered macbinary name */
- IOParam pb; /* io parameter block for rename */
- FileParam fileBlock; /* parameter block for setting finder info */
- char *ptr;
- char temp[64]; /* a string buffer */
- long err;
- short type;
- Handle item;
- Rect box;
-
- strcpy(temp,"Copy of ");
- strcpy(localname,p2cstr(&buff[1])); /* make c string */
-
- if( FindFile(localname,logFileRefNum)) /* whoops file already exists */
- { strcpy(localname,strcat(temp,localname)); /* extend name */
- if(FindFile(localname,logFileRefNum)) /* give up */
- FSDelete(localname,logFileRefNum);
- }
- /* here localname is an OK name for a file (if not too long) */
-
- /* rename the log file to reflect the macbinary name */
- err=Rename(logFileName,logFileRefNum,localname);
- if(err)ErrorMessage("Error During Rename",err);
-
- /* Put the new name up on the board */
- GetDItem(dlog,FILE_ITEM,&type,&item,&box);
- SetIText(item,localname);
-
-
- /* record the new name */
- strcpy(logFileName,localname);
-
- /* set default volume */
- memset(&pb,0,sizeof(IOParam));
- pb.ioRefNum = logFile;
- if(err=PBFlushFile(&pb,0))
- ErrorMessage("Error Flushing File",err);
-
-
- /* reset the finder info */
-
- memset(&fileBlock,0,sizeof(FileParam));
- fileBlock.ioNamePtr = c2pstr(localname);
- fileBlock.ioVRefNum = logFileRefNum;
- err = PBGetFInfo(&fileBlock,0);
- if(err)ErrorMessage("Error in GetFInfo",err);
-
- memcpy(&fileBlock.ioFlFndrInfo,&buff[65],10);
- memcpy(&fileBlock.ioFlCrDat,&buff[91],8);
-
- /* so the icons won't stack clear the inited bit */
- fileBlock.ioFlFndrInfo.fdFlags &= ~FLInit ;
-
- err = PBSetFInfo(&fileBlock,0);
- if(err)ErrorMessage("Error in SetFileInfo",err);
-
- }
-
- void ProcessBlock(buff,blkno)
- char buff[];
- long blkno;
- { static long dblks; /* the number of data blocks expected */
- static long rblks; /* the number of resource blocks expected */
- static long lastdbytes; /* number of bytes in last data block */
- static long lastrbytes; /* number of bytes in last resource block */
- static long binary; /* true if we discover macbinary format */
- static long dforklen; /* length of datafork in bytes */
- static long rforklen; /* length of resource fork in bytes */
- char temp[10];
- short i;
- Handle item;
- short type;
- Rect box;
-
- if(blkno==1) /* first sector tells all */
- if(buff[0] || buff[74] || buff[82]) /* is this a macbinary file? */
- { binary = 0; /* nope set flag to no binary */
- OutBlock(logFile,buff,sectorSize);
- return;
- }
- else /* this is a macbinary format file */
- { GetDItem(dlog,PROTOCOL_ITEM,&type,&item,&box);
- SetIText(item,"MacBinary");
- GetDItem(dlog,OF_ITEM,&type,&item,&box);
- SetIText(item,"Of");
- Message("Changing Log File Name");
- SetFileInformation(buff); /* set finder info & change name */
- memcpy(&dforklen,&buff[83],4);
- dblks = (dforklen+sectorSize-1)/sectorSize;
- lastdbytes = dforklen % sectorSize;
- if(!lastdbytes)lastdbytes = sectorSize;
- if(!dforklen)
- {FSClose(logFile); /* close data fork and open resource fork */
- logFile = 0;
- OpenRF(logFileName,logFileRefNum,&logFile);
- }
- memcpy(&rforklen,&buff[87],4);
- rblks = (rforklen +sectorSize-1)/sectorSize;
- gTotal = rblks+dblks+1;
- GetDItem(dlog,TOTAL_ITEM,&type,&item,&box);
- NumToString(gTotal,temp);
- SetIText(item,temp);
-
- lastrbytes = rforklen % sectorSize;
- if(!lastrbytes)lastrbytes = sectorSize;
-
- binary = 1;
- return;
- }
-
- if (!binary) { OutBlock(logFile,buff,sectorSize);return;}
-
- if (blkno == dblks+1) /* last block of data fork */
- { OutBlock(logFile,buff,lastdbytes);
- FSClose(logFile); /* close data fork and open resource fork */
- logFile = 0;
- OpenRF(logFileName,logFileRefNum,&logFile);
- return;
- }
-
- if (blkno == dblks+rblks+1) /* last resource block */
- { OutBlock(logFile,buff,lastrbytes); return;}
-
- OutBlock(logFile,buff,sectorSize); /* of the mill block */
-
- } /* ProcessBlock */
-
- /********************************************************************/
-
- short ReceiveFile()
- {
- IOParam pblock ;
- Point loc;
- SFReply reply;
-
- loc.v = 80;
- loc.h = 100;
-
-
- SFPutFile(&loc, "Log File", "LogFile", 0, &reply);
-
- if( reply.good )
- {
- /* if the reply was good then we must set the default volume */
-
- memset(&pblock,0,sizeof(IOParam));
- pblock.ioVRefNum = reply.vRefNum ;
- logFileRefNum = reply.vRefNum;
- PBSetVol(&pblock,0);
-
- p2cstr(&reply.fName); /* convert to c format */
-
- strcpy(logFileName,&reply.fName); /* save copy for delete */
- FSDelete(logFileName,logFileRefNum);
-
- /* Open the target file */
-
- Create(logFileName,logFileRefNum,creator,'TEXT');
- FSOpen(logFileName,logFileRefNum,&logFile);
- return 1;
-
- } /* good reply */
- return 0;
- }
-
-
- /********************************************************************/
-
- short Sendfile()
- {
- Point loc;
- IOParam pblock ;
- SFTypeList typeList;
- SFReply reply;
- short ntypes;
- OSErr err;
-
- loc.v = 80;
- loc.h = 100;
- ntypes = (MacBinary)? -1:1; /* allow all files if MacBinary true */
-
- typeList[0] = 'TEXT';
-
- SFGetFile(&loc, 0, 0, ntypes, typeList, 0, &reply);
-
- if( reply.good )
- {
- /* if the reply was good then set the default volume */
-
- memset(&pblock,0,sizeof(IOParam));
- pblock.ioVRefNum = reply.vRefNum ;
- PBSetVol(&pblock,0);
-
- p2cstr(&reply.fName); /* convert to c format */
-
- thefileRefNum = reply.vRefNum;
- strcpy(thefilename,&reply.fName); /* save copy for open */
-
- /* Open the target file */
- if(err = FSOpen(thefilename,thefileRefNum,&thefile)){
- ErrorMessage("Can't Open File",err);
- return 0;
- }
- /* compute the size of the transfer in blocks...if macbinary
- this number will be changed
- */
- GetEOF(thefile,&gTotal);
- gTotal = ( gTotal+sectorSize-1)/sectorSize;
-
-
- return 1;
- } /* good reply */
- return 0 ;
- } /* GetAfile */
- /********************************************************************/
- void BadData(err,crc)
- short *err;
- short crc; /* true if attempting to tell sender to use CRC */
- { char trash;
-
- /* eat garbage until line is quiet */
- while(TimedRead(sIn,&trash,1,1));
-
- if (!crc) OutCh(sOut,NAK); /* signal error */
- else OutCh(sOut,CRCCHAR); /* request CRC transmission */
-
- if((*err)++ >= ERRLIM) longjmp(env,3); /* give up*/
- }
- /********************************************************************/
-
- short BlockTimedRead(buff,count,limit)
- char *buff; /* data goes here */
- short count; /* this many characters */
- long limit; /* timeout value in seconds */
-
- { IOParam rBlock ; /* block for describing read */
- CntrlParam kBlock ; /* block for the Killio call */
- long theLimit; /* read must complete by this time */
- EventRecord event; /* check for mouse down */
- short giveup; /* set to true if mousedown detected */
-
- /* set up for asynch read */
- rBlock.ioCompletion = 0 ; /* no completion routine */
- rBlock.ioVRefNum = 0;
- rBlock.ioRefNum = sIn; /* select read port */
- rBlock.ioBuffer = buff; /* where to read to */
- rBlock.ioReqCount = count; /* byte count to read */
- rBlock.ioPosMode = 0;
-
- PBRead(&rBlock,1); /* post asynch read */
-
- /* wait for the read to complete or for a timeout */
- theLimit = *( long *)0x20c + limit ; /* compute due time */
-
- /* here we can update the clock and check for a user cancel */
-
- giveup = 0;
- if(GetNextEvent(mDownMask,&event)) giveup =1; /* give up */
- if(showClock)
- if (GetNextEvent(app2Mask,&event))showTime(); /* adjust clock */
-
-
- /* wait */
- while((rBlock.ioResult == 1) && (theLimit >= *( long *)0x20c));
-
-
- /* how have we escaped? */
- if(rBlock.ioResult == 0) return 1; /* read has completed */
-
- /* here if timeout or error during read...Killio to cleanup */
- kBlock.ioCompletion = 0;
- kBlock.ioCRefNum = sIn;
-
- PBKillIO(&kBlock,0); /* synch */
-
- /* if we detected a mousedown while waiting then abort */
- if (giveup) longjmp(env,4);
-
-
- return 0; /* signify error */
- }
- /********************************************************************/
-
- void Xreceive()
- { char buff[1024+10];
- char c;
- char blk,notBlk; /* block number and its complement */
- short errCount; /* cumulative errors for one block */
- char blockNumber; /* expected blocknumber */
- static long total; /* total blocks received */
- char RcheckSum; /* received checksum */
- char checkSum; /* calculated checksum */
- short error; /* error code for catchsignal */
- short i; /* for loop index */
- short crcMode; /* true if expecting CRC */
- short firstSOH; /* true until we receive first SOH */
- short readSize; /* Size of packet to get */
- IOParam pblock; /* parameter block for vol flush */
- EventRecord event; /* catches mousedown to cancel */
- Rect box; /* temp for getditem */
- short type; /* temp storage */
- Handle item; /* temp handle storage */
- Handle blockNumH; /* handle to item to show current block */
- char temp[10]; /* storage for converting integers */
- static WindowPtr old; /* previous graphport */
- static long stime,ftime;/* start and finish time in ticks */
- unsigned short crcVal; /* for the crc */
-
-
- /* ask the user to select a file, if he quits so do we */
- if(!ReceiveFile()){OutCh(sOut,CAN);OutCh(sOut,CAN);return ; }
-
-
- /* bring the progress dialog */
- GetPort(&old); /* remember the port */
- HideWindow(myWindow); /* hide the tty window */
-
- /* create the dialogue */
- dlog = (DialogPtr)GetNewDialog(PROGRESS_ID ,0,(WindowPtr)-1);
-
- DrawDialog(dlog);
-
- /* get a handle to the status field for ease of access */
-
- GetDItem(dlog,STATUS_ITEM,&type,&statusHandle,&box);
- GetDItem(dlog,BLOCK_ITEM,&type,&blockNumH,&box);
-
- /* set some fields */
- GetDItem(dlog,TRANS_ITEM,&type,&item,&box);
- SetIText(item,"Receiving");
- GetDItem(dlog,PROTOCOL_ITEM,&type,&item,&box);
- if(TextXMode)SetIText(item,"Text Xmodem");
- else SetIText(item,"Xmodem");
- GetDItem(dlog,ERROR_ITEM,&type,&item,&box);
- if(fastDL)SetIText(item,"Checksum,Abort On Error");
- else SetIText(item,"Eight Bit Checksum With ARQ");
- GetDItem(dlog,FILE_ITEM,&type,&item,&box);
- SetIText(item,logFileName);
- Message("Waiting For Handshake");
-
- /* ready to go but first let's establish an error handler */
- if( error = setjmp(env))
- { DisposDialog(dlog); ShowWindow(myWindow);SetPort(old);
- switch(error)
- { case 1:drawCString("\r*** Transmitter Cancel***\012");break;
- case 2: ftime = TickCount(); /* normal exit */
- FSClose(logFile);logFile = 0;
- drawCString("\r***Transfer Completed***\r\012");
- NumToString(sectorSize*(total-1),temp);
- drawCString(temp);
- drawCString(" user bytes received.");
- drawCString(" Effective Transfer Rate = ");
- NumToString((sectorSize*(total-1)*60)/(ftime-stime),temp);
- drawCString(temp);
- drawCString(" bytes/second.\r\012");
-
- OutCh(sOut,ACK);OutCh(sOut,ACK);
-
- /* make sure we have the file if we later crash */
- memset(&pblock,0,sizeof(IOParam));
- pblock.ioVRefNum = logFileRefNum ;
- PBFlushVol(&pblock,0);
-
- SysBeep(7);SysBeep(7);
- return;
- case 3: NumToString(total,temp);
- buff[0]=0;
- strcpy(buff,"Too Many Errors For Block ");
- strcat(buff,temp);
- drawCString(buff);
- OutCh(sOut,CAN);
- break;
- case 4:drawCString("\rReceiver Cancelled Transfer");
- OutCh(sOut,CAN);
- break;
- case 6: drawCString("\r***file system error***");break;
- default:drawCString("\r***Unknown Signal***");break;
- }
- FSClose(logFile);logFile = 0;
- FSDelete(logFileName,logFileRefNum);
- SysBeep(7);SysBeep(7);
- return;
- } /* end of handler */
-
- /* user selected a file so lets crank up the transmitter */
- blockNumber = 1; total = 1;
- errCount = 0; firstSOH = 1;
- if(forceCheckSum)crcMode = 0;else crcMode =1;
- BadData(&errCount,crcMode); /* this will send a NAK/C to crank up the other side */
-
- while(true)
- {
- if(!TimedRead(sIn,&c,1,NAKTIM)) /* wait for a charcter */
- { Message("Timeout waiting for SOH");
- BadData(&errCount,crcMode);
- if(firstSOH && (errCount>=3)) crcMode = 0;
- continue;}
-
- /* examine the captured character */
- switch(c)
- { case NUL: continue; /* skip nulls */
- case CAN: longjmp(env,1); /* transmitter gave up */
- case EOT: longjmp(env,2); /* we are done */
- case SOH: break; /* start of block let's go! */
- default : Message("Bad Character, Expected SOH");
- BadData(&errCount,crcMode);
- /* give the transmitter 3 shots at recognizing CRC */
- if ((errCount >= 3) && firstSOH) crcMode = 0;
- continue;
- }
-
- /* pick up the rest of the packet */
- if (firstSOH && crcMode) {
- GetDItem(dlog,ERROR_ITEM,&type,&item,&box);
- if(fastDL)SetIText(item,"CRC, Abort on Error");
- else SetIText(item,"CCITT-CRC With ARQ");
- }
-
- if(firstSOH) stime = TickCount(); /* sample the clock */
-
- firstSOH = 0; /* pay no attention to recognizing mode */
-
- if (crcMode) readSize = sectorSize + 4;
- else readSize = sectorSize + 3;
-
-
- if(!BlockTimedRead(buff,readSize,NAKTIM))
- { Message("Timeout waiting for data");
- BadData(&errCount,crcMode); continue ;}
-
- /* if the user selected fast download then send back an ACK */
- if(fastDL)OutCh(sOut,ACK); /* acknowlege the block */
-
- /* check for a scrambled block */
- if ( buff[0] != ~buff[1])
- if(fastDL) longjmp(env,4); /* give up on this option */
- else
- { Message("Error,scrambled block number");
- BadData(&errCount,crcMode); continue;}
-
- /* check the checksum */
- if (crcMode)
- {
- crcVal = table_driven_crc(0,&buff[2],sectorSize+2,crc_table);
- if ((crcVal & 0xFFFF) != 0)
- if(fastDL) longjmp(env,4);
- else
- { Message("Bad CRC");
- BadData(&errCount,crcMode);
- continue;
- }
- }
- else
- {
- if ( buff[sectorSize+2] != CheckSum(&buff[2],sectorSize))
- if(fastDL) longjmp(env,4);
- else
- { Message("Bad Checksum");
- BadData(&errCount,crcMode); continue;}
- }
-
- /* if this block is the previous block then ACK but don't write */
- if ( buff[0] == blockNumber-1)
- if(fastDL)continue;
- else
- { OutCh(sOut,ACK); continue;}
-
- /* if this block is not the expected block then bad block */
- if ( buff[0] != blockNumber)
- if(fastDL) longjmp(env,4);
- else
- { Message("Out of sequence blocknumber");
- BadData(&errCount,crcMode); continue;}
-
- /* if we get here we have the validated expected block */
-
-
- if(!fastDL)OutCh(sOut,ACK); /* acknowlege the block */
-
- if (MacBinary) ProcessBlock(&buff[2],total);
- else
- if(TextXMode){ /* pitch any LF's, Nulls and control Z's */
- for(i=0;i<sectorSize;i++)
- if((buff[i+2]!=LF) && (buff[i+2]!=0)
- && (buff[i+2]!= CTLZ))OutCh(logFile,buff[i+2]);
- }
- else /* plain output */
- OutBlock(logFile,&buff[2],sectorSize);
- NumToString(total,temp);
- SetIText(blockNumH,temp);
- Message("Ok");
-
- blockNumber++; /* kick the block number */
- total++; /* and the total */
- errCount = 0 ; /* reset the error counter */
- } /* go get another block */
- } /* end of Xreceive */
-
- Boolean eof(chan) /* true if mark >= eof */
- short chan; /* refNum of open file */
- { FCBPBRec pb;
- OSErr err;
-
- memset(&pb,0,sizeof(FCBPBRec)); /* clear parameter block */
- pb.ioRefNum = chan;
- if(err = PBGetFCBInfo(&pb,false))
- { ErrorMessage("Error in GetFCBInfo",err); return true;}
- if(pb.ioFCBCrPs >= pb.ioFCBEOF) return true;
- return false;
- }
- /********************************************************************/
- short ReadTextSector(chan,buff,blkno)
- short chan;
- char buff[];
- long blkno;
- { static char flag; /* true -> last block ended with a CR */
- char ch;
- short i;
- long cnt;
-
- if(blkno==1) flag = 0; /* initialize flag */
- i = 0;
-
- if(flag)buff[i++] = LF; /* start block with LF */
- flag = 0; /* reset the flag */
-
- if(eof(chan) && (i==0)) return 0; /* finished ! */
-
- while(i < sectorSize)
- if( eof(chan)) buff[i++] = 0; /* fill remainder with nulls */
- else {
- cnt = 1;
- FSRead(chan,&cnt,&ch); buff[i++] =ch;
- if((ch== CR)&&(i==sectorSize))flag = 1;
- else if(ch==CR) buff[i++]=LF;
- }
- return 1; /* more to do */
- }
- /********************************************************************/
-
- short ReadSector(chan,buff)
- short chan;
- char buff[];
- { short i;
- long count;
- OSErr err;
- char temp[10];
- long pos;
-
- count = sectorSize;
- if(err = FSRead(chan,&count,buff))
- if(err != eofErr) ErrorMessage("Read Reading File",err);
-
- /* NumToString(count,temp);Message(temp);
-
- GetFPos(chan,&pos);
- NumToString(count,temp);Message(temp);
- */
- if(count > 0){
- if(count != sectorSize)
- for(i=count;i<sectorSize;i++) buff[i]=0; /* pad with nulls */
- return 1 ;
- }
- else return 0; /* eof */
- }
- /********************************************************************/
- short GetBlock(buff,blkno)
- char buff[]; /* the array to fill */
- long blkno ; /* the current block number */
- { static long dblk = -1; /* total number of data blocks to send */
- long rblks; /* total number of resourced blocks to send */
- FileParam fileBlock;/* for getfile info */
- short err; /* error catcher */
- short type;
- Handle item;
- Rect box;
- char temp[10];
-
- if (MacBinary && (blkno==1))
- { memset(buff,0,sectorSize);
- memset(&fileBlock,0,sizeof(FileParam));
-
- fileBlock.ioNamePtr = c2pstr(thefilename);
- fileBlock.ioVRefNum = thefileRefNum;
-
- /* get the info about the file */
- if(err = PBGetFInfo(&fileBlock,0))
- ErrorMessage("Error getting file info,GetBlock",err);
- /* restore the filename */
- p2cstr(thefilename);
-
- /* set up the first block */
-
- /* collect the finder info */
- memcpy(&buff[65],&fileBlock.ioFlFndrInfo,16);
- buff[74] = (char) 0; /* keep this location clear */
-
- /* the creation and modification dates */
- memcpy(&buff[91],&fileBlock.ioFlCrDat,8);
-
- /* move the file name */
- buff[1] = strlen(thefilename);
- memcpy(&buff[2],thefilename,buff[1]);
-
- memcpy(&buff[83],&fileBlock.ioFlLgLen,4); /* data size */
- memcpy(&buff[87],&fileBlock.ioFlRLgLen,4);/* resource size */
-
- dblk = (fileBlock.ioFlLgLen+sectorSize-1)/sectorSize;
- rblks= (fileBlock.ioFlRLgLen+sectorSize-1)/sectorSize;
- gTotal = 1+dblk+rblks;
-
- GetDItem(dlog,TOTAL_ITEM,&type,&item,&box);
- NumToString(gTotal,temp);
- SetIText(item,temp);
-
- /* I don't know how to find the Protect Bit */
-
- if(!dblk) /* no data fork */
- { FSClose(thefile); thefile = 0;
- if(err=OpenRF(thefilename,thefileRefNum,&thefile))
- Message("Error Opening Resource Fork");
- if(err=SetFPos(thefile,fsFromStart,0))
- Message("error setting fpos");
- }
-
- /* more to do */
- return 1;
- }
-
- if (MacBinary && (blkno == 1+dblk)) /* last data block */
- { ReadSector(thefile,buff); /* get a block */
- FSClose(thefile); /* close data fork */
- thefile = 0;
- if(err=OpenRF(thefilename,thefileRefNum,&thefile))
- Message("Error Opening Resource fork");
- if(err=SetFPos(thefile,fsFromStart,0))
- Message("Error Setting FPos");
- return 1; /* eof on resource fork will stop everything */
- }
-
- /* if we get here we have a run of the mill block */
- if(TextXMode) return ReadTextSector(thefile,buff,blkno);
- else return ReadSector(thefile,buff);
-
- }
-
- /********************************************************************/
-
- char waitStart(chan)
- short chan;
- { char c;
- short inTime;
- short nakWait;
-
- nakWait = 0;
- do
- {inTime = TimedRead(chan,&c,1,NAKLIM); /* wait NAKLIM seconds */
- if(!inTime)
- {if (++nakWait >= 10) Cancel(chan,1); /* this won't come back */
- continue; /* try for NAK again */
- }
- else
- switch(c)
- { case CAN: Cancel(chan,2); break;
- case NAK: return 0; /* let's go! */
- case CRCCHAR:if(!forceCheckSum) return 1; /* note fall through */
- default: if( nakWait++ >=10) Cancel(chan,3); continue;
- }
- }
- while(true);
- }
- /********************************************************************/
-
- short GetAck(chan,err)
- short chan;
- short *err;
- { char c;
- short inTime;
- long cnt;
-
- /* flush input buffer */
- while (ChAvail(chan)){cnt = 1; FSRead(chan,&cnt,&c);}
-
- inTime = TimedRead(chan,&c,1,ACKLIMTIM);
-
- if( inTime && (c == ACK)) return 1; /* success */
- else
- { if( (*err)++>=ERRLIM) Cancel(chan,4); /* too many errors for this sector */
- return 0; /* failure */
- }
- }
- /********************************************************************/
-
- void Xsend()
- { short error; /* from signal */
- short moreToSend; /* true->file not exhausted */
- char buff[1024+3]; /* next chunk of file Plus block header */
- char blockNumber;
- char checkSum;
- short errorCount; /* accumulator for sector errors */
- short i;
- char crcMode;
- long total; /* current block number */
- EventRecord event; /* gets mousedown event to cancel */
- short type;
- Handle item;
- Rect box;
- static WindowPtr old ; /* previous port */
- char temp[10] ; /* conversion storage */
- Handle blockNumH;
- IOParam rBlock ; /* for asynch write */
- IOParam ckBlock; /* for sending checksum/crc */
- static long stime,ftime; /* start and finish times (ticks) */
- unsigned short theCRC;
-
- dlog = (DialogPtr) 0;
-
-
- if(!Sendfile()){
- OutCh(sOut,CAN);return; } /* user changed mind */
-
-
- /* put up the dialog box */
- GetPort(&old); /* save old port */
- HideWindow(myWindow); /* hide the tty window */
- dlog = GetNewDialog(PROGRESS_ID ,0,(WindowPtr)-1); /* create the dialogue */
-
- DrawDialog(dlog);
-
- /* get a handle to the status field for ease of access */
-
- GetDItem(dlog,STATUS_ITEM,&type,&statusHandle,&box);
- GetDItem(dlog,BLOCK_ITEM,&type,&blockNumH,&box);
-
- /* set some fields */
- GetDItem(dlog,TRANS_ITEM,&type,&item,&box);
- SetIText(item,"Sending");
-
- GetDItem(dlog,PROTOCOL_ITEM,&type,&item,&box);
- if(MacBinary)SetIText(item,"MacBinary");
- else if(TextXMode) SetIText(item,"Text Xmodem");
- else SetIText(item,"Xmodem");
-
- GetDItem(dlog,FILE_ITEM,&type,&item,&box);
- SetIText(item,thefilename);
-
- GetDItem(dlog,OF_ITEM,&type,&item,&box);
- if (TextXMode) SetIText(item,"Of About");
- else SetIText(item,"Of");
-
- GetDItem(dlog,TOTAL_ITEM,&type,&item,&box);
- NumToString(gTotal,temp);
- SetIText(item,temp);
- Message("Waiting For Handshake");
-
- /* establish an error handler */
- if(error = setjmp(env))
- {if(dlog){
- DisposDialog(dlog);ShowWindow(myWindow);SetPort(old);}
- switch(error)
- { case 1:drawCString("\r*** Host not transmitting. ***"); break;
- case 2:drawCString("\r*** Host sent initial CAN. ***"); break;
- case 3:drawCString("\r*** Host not transmitting NAK or CAN ***");break;
- case 4:drawCString("\r*** Too many errors for block ");
- NumToString(total,temp);
- drawCString(temp);
- drawCString(" ***");
- break;
- case 5:drawCString("\r*** User aborted send. ***");
- OutCh(sOut,CAN);
- break;
- case 6:drawCString("\r*** File System Error ***");
- OutCh(sOut,CAN);
- break;
- default:drawCString("\r*** Undefined error. ***"); break;
- }
- FSClose(thefile); thefile = 0;
- SysBeep(7);SysBeep(7);
- return;
- } /* end of error handler */
-
- crcMode = waitStart(sIn); /* wait for NAK or C */
-
- GetDItem(dlog,ERROR_ITEM,&type,&item,&box);
- if (crcMode)SetIText(item,"CCITT-CRC With ARQ");
- else SetIText(item,"Eight Bit CheckSum");
-
- blockNumber = 1;total = 1; stime = TickCount();
- do
- { if(GetBlock(&buff[3],total))
- { errorCount = 0;
- do {
-
- buff[0] = SOH;
- buff[1] = blockNumber;
- buff[2] = ~blockNumber;
-
- /* set up for write */
- rBlock.ioCompletion = 0 ; /* no completion routine */
- rBlock.ioVRefNum = 0;
- rBlock.ioRefNum = sOut; /* select read port */
- rBlock.ioBuffer = buff; /* where to write from */
- rBlock.ioReqCount = sectorSize+3; /* byte count to write */
- rBlock.ioPosMode = 0;
-
- PBWrite(&rBlock,1); /* post asynch write */
-
-
- /* while the block is being sent do other stuff */
-
- if(GetNextEvent(mDownMask,&event))
- { /* need to kill io here */
- longjmp(env,5);
- }
-
- if(showClock)
- if (GetNextEvent(app2Mask,&event))showTime(); /* adjust clock */
-
-
- NumToString(total,temp);
- SetIText(blockNumH,temp);
-
- if(errorCount)Message("Retransmitting Block");
- else Message("");
-
- if (crcMode)
- theCRC = table_driven_crc(0,&buff[3],sectorSize,crc_table);
- else
- checkSum = CheckSum(&buff[3],sectorSize);
-
-
-
- /* set up for write of checksum/crc */
- ckBlock.ioCompletion = 0 ; /* no completion routine */
- ckBlock.ioVRefNum = 0;
- ckBlock.ioRefNum = sOut; /* select read port */
- ckBlock.ioBuffer = (crcMode)?(char *) &theCRC :(char *) &checkSum; /* where to write from */
- ckBlock.ioReqCount = (crcMode)?2:1; /* byte count to write */
- ckBlock.ioPosMode = 0;
-
- PBWrite(&ckBlock,0); /* when this completes we are done */
-
-
- } /* check for an ACK */
- while(!GetAck(sIn,&errorCount)) ; /* retransmit block if no ACK */
- blockNumber++; /* set up for next block */
- total++ ;
- }
- else /* file transmission is complete notify receiver and quit */
- { errorCount = 0;ftime = TickCount();
- do OutCh(sOut,EOT) ; while(!GetAck(sIn,&errorCount));
- FSClose(thefile);thefile=0;
- DisposDialog(dlog);ShowWindow(myWindow);SetPort(old);
- drawCString("\r\012***Transmission Complete***\r\012");
- NumToString(sectorSize*(total-1),temp);
- drawCString(temp);
- drawCString(" user bytes sent.");
- drawCString(" Effective Transmission Rate =");
- NumToString((sectorSize*(total-1)*60)/(ftime-stime),temp);
- drawCString(temp);
- drawCString(" bytes/second\r\012");
- SysBeep(7);SysBeep(7);
- return ; /* to the main program */
- }
- }
- while (true);
- }
-